package com.fotoloka.services.impl;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;

import com.fotoloka.processor.CVImageProcessor;
import com.fotoloka.services.WebCam;
import com.fotoloka.util.Cronometro;
import com.fotoloka.view.ImagePanel;
import com.googlecode.javacv.Frame;
import com.googlecode.javacv.FrameGrabber.Exception;
import com.googlecode.javacv.FFmpegFrameRecorder;
import com.googlecode.javacv.FrameRecorder;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.IplImage;

/**
 * Serviço para obter as informações da OpenCVWebCam
 * 
 * @author Pablo
 * 
 */
@SuppressWarnings("serial")
public class OpenCVWebCam extends ImagePanel implements WebCam {

	private final static String[] LIBS = {
		"cv210.dll",
		"cvaux210.dll",
		"cxcore210.dll",
		"cxts210.dll",
		"highgui210.dll",
		"ml210.dll"
		};
	
	private boolean running = false;

	private Thread runner = null;
	
	private boolean pause = false;

	private OpenCVFrameGrabber grabber;

	private CVImageProcessor imageProcessor = null;

	private BufferedImage image;

	private Integer device;

	private int width;

	private int height;
	
//	private FrameRecorder recorder;

	public OpenCVWebCam(int device, int width, int height) throws Exception {
		this.device = device;
		this.width = width;
		this.height = height;
		this.setBackground(Color.white);
		criarGrabber();
	}

	private void criarGrabber() throws Exception {
		//define path das dlls
		File faPath = new File("lib");
		System.setProperty("jna.library.path", faPath.getAbsolutePath());
		
		this.grabber = new OpenCVFrameGrabber(this.device);
		grabber.setBitsPerPixel(100);
		grabber.setImageWidth(this.width);
		grabber.setImageHeight(this.height);
		//grabber.start();
		
	}
	
	
	

	/**
	 * Inicia o grabbing frames from the webcam.
	 * 
	 * @throws Exception
	 */
	@Override
	public void start() throws Exception {
		if (running)
			return;

		grabber.start();
		
//		try {
//			recorder = FFmpegFrameRecorder.createDefault("c:\\temp\\out.avi", 640, 480);
//			recorder.setFrameRate(25);
//			recorder.start();
//		} catch (com.googlecode.javacv.FrameRecorder.Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}

		running = true;
		runner = new Thread() {
			public void run() {
				while (running) {
					grabAndPaint();
					try {
						Thread.sleep(20); //20 quadros por segundo
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					Thread.yield();
				}
				try {
					grabber.stop();
				} catch (Exception e) {
					e.printStackTrace();
				}
				runner = null;
			}
		};
		runner.start();
	}

	private void grabAndPaint() {
		try {
			// grab the raw image from the webcam
			grabber.setBitsPerPixel(100);
			grabber.setImageWidth(width);
			grabber.setImageHeight(height);
			
			IplImage frame = grabber.grab();
//			recorder.setFrameRate(20);
//			try {
//				recorder.record(frame);
//			} catch (com.googlecode.javacv.FrameRecorder.Exception e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
			
			if(!pause) {
				Cronometro bateFoto = new Cronometro("Processor");
				// if an image processor has been defined, start processing the
				// image
				if (imageProcessor != null)
					frame = imageProcessor.process(frame);
	
				// output the final result as a bufferedimage
				image = frame.getBufferedImage();
				bateFoto.stop();
			}
			
			this.setImage(image);
		} catch (Exception e) {
			e.printStackTrace();
		}
		Cronometro rePaint = new Cronometro("Repaint");
		this.repaint();
		rePaint.stop();
	}

	@Override
	public boolean isRunnning() {
		return runner != null;
	}

	@Override
	public void stop() {
		running = false;
//		try {
//			recorder.stop();
//			System.out.println("filmagem terminada");
//		} catch (com.googlecode.javacv.FrameRecorder.Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
	}

	public CVImageProcessor getImageProcessor() {
		return imageProcessor;
	}

	public void setImageProcessor(CVImageProcessor imageProcessor) {
		this.imageProcessor = imageProcessor;
	}

	@Override
	public BufferedImage getImage() {
		return image;
	}

	@Override
	public int getDevice() {
		return device;
	}

	@Override
	public void setDevice(int device) {
		this.device = device;
	}

	public boolean isPause() {
		return pause;
	}

	public void setPause(boolean pause) {
		this.pause = pause;
	}

	/*
	 * 
	 * public BufferedImage getImage() { try { BufferedImage image;
	 * 
	 * grabber.setBitsPerPixel(100); grabber.setImageWidth(this.width);
	 * grabber.setImageHeight(this.height); IplImage frame = grabber.grab();
	 * image = frame.getBufferedImage();
	 * 
	 * return image; } catch (Exception e) { throw new
	 * RuntimeException("Erro ao obter imagem da webcam.", e); }
	 * 
	 * }
	 * 
	 * public void close() { try { this.grabber.stop(); } catch (Exception e) {
	 * e.printStackTrace(); } }
	 * 
	 * public Integer getDevice() { return device; }
	 * 
	 * public void setDevice(Integer device) { this.device = device; }
	 * 
	 * public Integer getWidth() { return width; }
	 * 
	 * public void setWidth(Integer width) { this.width = width; }
	 * 
	 * public Integer getHeight() { return height; }
	 * 
	 * public void setHeight(Integer height) { this.height = height; }
	 * 
	 * public OpenCVFrameGrabber getGrabber() { return grabber; }
	 */

}
